package com.guocloud.medimind.utils;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.io.*;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;

/**
 * 文本编码转换工具
 * 用于处理不同编码格式的文本文件
 */
@Slf4j
@Component
public class TextEncodingConverter {

    /**
     * 尝试多种编码格式来正确读取文本
     * @param text 可能存在乱码的文本
     * @return 修复后的文本，如果无法修复则返回原文本
     */
    public String fixEncoding(String text) {
        if (text == null || text.isEmpty()) {
            return text;
        }
        
        // 如果文本中包含大量乱码字符，可能是编码问题
        if (containsGarbledCharacters(text)) {
            log.info("检测到可能的乱码文本，尝试修复编码...");
            
            // 尝试不同的编码组合修复
            String[] possibleSourceEncodings = {"GBK", "GB2312", "ISO-8859-1", "Windows-1252"};
            
            for (String sourceEncoding : possibleSourceEncodings) {
                try {
                    // 假设文本是以sourceEncoding编码后被当做UTF-8解读的
                    byte[] bytes = text.getBytes(StandardCharsets.UTF_8);
                    String decodedText = new String(bytes, Charset.forName(sourceEncoding));
                    
                    // 再次以正确的编码转为UTF-8
                    bytes = decodedText.getBytes(Charset.forName(sourceEncoding));
                    String fixedText = new String(bytes, StandardCharsets.UTF_8);
                    
                    // 如果修复后的文本不再含有大量乱码字符，则认为修复成功
                    if (!containsGarbledCharacters(fixedText)) {
                        log.info("文本编码已修复，原编码可能是：{}", sourceEncoding);
                        return fixedText;
                    }
                } catch (Exception e) {
                    log.warn("使用{}编码修复文本失败", sourceEncoding, e);
                }
            }
            
            log.warn("无法自动修复文本编码");
        }
        
        return text;
    }
    
    /**
     * 从文件读取文本，自动处理编码问题
     * @param file 文本文件
     * @return 正确编码的文本内容
     */
    public String readFileWithCorrectEncoding(File file) throws IOException {
        // 尝试不同的编码读取文件
        String[] encodings = {"UTF-8", "GBK", "GB2312", "ISO-8859-1", "Windows-1252"};
        
        String content = null;
        IOException lastException = null;
        
        for (String encoding : encodings) {
            try (BufferedReader reader = new BufferedReader(
                    new InputStreamReader(new FileInputStream(file), encoding))) {
                
                StringBuilder sb = new StringBuilder();
                String line;
                while ((line = reader.readLine()) != null) {
                    sb.append(line).append("\n");
                }
                
                content = sb.toString();
                
                // 如果读取的内容没有明显的乱码字符，则认为找到了正确的编码
                if (!containsGarbledCharacters(content)) {
                    log.info("成功使用{}编码读取文件", encoding);
                    return content;
                }
            } catch (IOException e) {
                lastException = e;
                log.debug("使用{}编码读取文件失败", encoding, e);
            }
        }
        
        // 如果所有编码都尝试过，但仍然有乱码，返回最后一次读取的内容
        if (content != null) {
            log.warn("无法找到完全正确的编码，返回最后尝试的结果");
            return content;
        }
        
        // 如果所有尝试都失败，抛出最后一个异常
        if (lastException != null) {
            throw lastException;
        }
        
        throw new IOException("无法读取文件内容");
    }
    
    /**
     * 判断文本是否包含乱码字符
     * @param text 要检查的文本
     * @return 是否包含乱码字符
     */
    private boolean containsGarbledCharacters(String text) {
        if (text == null) {
            return false;
        }
        
        // 乱码字符的常见特征
        int garbledCount = 0;
        for (char c : text.toCharArray()) {
            // 常见乱码字符如 �
            if (c == '�' || c == '□' || c == '?' || 
                (c >= 0xFFFD && c <= 0xFFFF) || // Unicode 替换字符
                (c >= 0x80 && c <= 0x9F && c != 0x9D)) { // 控制字符
                garbledCount++;
            }
        }
        
        // 如果乱码字符超过总字符数的5%，认为存在乱码
        return garbledCount > text.length() * 0.05;
    }
} 